package com.teapos.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.teapos.dao.ProductDao;
import com.teapos.dao.QRcodeDao;
import com.teapos.dao.ShiftDao;
import com.teapos.dao.TakeStockDao;
import com.teapos.enumtype.ProductSortEnum;
import com.teapos.enumtype.ShiftStatusEnum;
import com.teapos.enumtype.TakeStockStatusEnum;
import com.teapos.enumtype.TradeTypeEnum;
import com.teapos.util.BusinessTool;
import com.teapos.util.Maps;
import com.teapos.util.Tool;

@SuppressWarnings({"rawtypes", "unchecked"})
@Service
public class ShiftService {
	
	@Autowired
	private ShiftDao shiftDao;
	@Autowired
	private QRcodeDao qRcodeDao;
	@Autowired
	private ProductDao productDao;
	@Autowired
	private TakeStockDao takeStockDao;
	
	public Map summaryShiftInfo(int storeId) {
		Map shift = shiftDao.getLastShiftRecord(storeId);
		Map param = new HashMap();
		param.put("storeId", storeId);
		BigDecimal leftAmount = new BigDecimal("0.00");
		if(shift!=null) {
			leftAmount = Tool.toBigDecimal(shift.get("left_amount"));
			param.put("time", shift.get("check_time"));
		}
		
		Map stockMap = shiftDao.summaryStock(param);
		Map param2 = new HashMap();
		param2.putAll(param);
		param2.put("type", 5);
		//出
		Map outTransferMap = shiftDao.summaryTransfer(param2);
		param2.put("type", 6);
		//入
		Map inTransferMap = shiftDao.summaryTransfer(param2);
		param2.put("type", TradeTypeEnum.BUY.getCode());
		Map buybackItemMap = shiftDao.summaryOrderItemCount(param2);
		
		Map saleMap = shiftDao.summaryAmountByType(Maps.put(param, "type", TradeTypeEnum.SCAT.getCode()));
		if(saleMap==null) saleMap = new HashMap();
		BigDecimal saleCashAmount = Tool.toBigDecimal(saleMap.get("cash_amount"));
		BigDecimal saleBankAmount = Tool.toBigDecimal(saleMap.get("bank_amount"));
		BigDecimal salePayAmount = Tool.toBigDecimal(saleMap.get("pay_amount"));
		Map advanceMap = shiftDao.summaryAdvanceAmount(Maps.put(param, "type", TradeTypeEnum.BEFORE.getCode()));
		if(advanceMap==null) advanceMap = new HashMap();
		BigDecimal advanceCashAmount = Tool.toBigDecimal(advanceMap.get("cash_amount"));
		BigDecimal advanceBankAmount = Tool.toBigDecimal(advanceMap.get("bank_amount"));
		BigDecimal advancePayAmount = Tool.toBigDecimal(advanceMap.get("pay_amount"));
		
		BigDecimal sumCashAmount = saleCashAmount.add(advanceCashAmount);
		BigDecimal sumBankAmount = saleBankAmount.add(advanceBankAmount);
		BigDecimal sumSaleAmount = salePayAmount.add(advancePayAmount);
		
		Map backMap = shiftDao.summaryAmountByType(Maps.put(param, "type", TradeTypeEnum.BUY.getCode()));
		if(backMap==null) backMap = new HashMap();
		BigDecimal backCashAmount = Tool.toBigDecimal(backMap.get("cash_amount"));
		BigDecimal backBankAmount = Tool.toBigDecimal(backMap.get("bank_amount"));
		//BigDecimal backPayAmount = Tool.toBigDecimal(backMap.get("pay_amount"));
		Map dailyMap = shiftDao.summaryDailyExpense(param);
		if(dailyMap==null) dailyMap = new HashMap();
		BigDecimal dailyAmount = Tool.toBigDecimal(dailyMap.get("amount"));
		
		Map imprestMap = shiftDao.summaryImprestAmount(param);
		if(imprestMap==null)imprestMap = new HashMap();
		BigDecimal imprestAmount = Tool.toBigDecimal(imprestMap.get("amount"));
		
		BigDecimal shouldHandAmount = sumSaleAmount.add(imprestAmount).add(leftAmount).subtract(backCashAmount).subtract(dailyAmount);
		BigDecimal left = shouldHandAmount.subtract(new BigDecimal("5000.00"));
		BigDecimal zero = new BigDecimal(0);
		BigDecimal realHandAmount = left.compareTo(zero)==-1?zero:left;
		return new Maps().put("sum_sale_amount", sumSaleAmount).put("sum_cash_amount", sumCashAmount)
				.put("sale_cash_amount", saleCashAmount).put("advance_cash_amount", advanceCashAmount)
				.put("sum_bank_amount", sumBankAmount)
				.put("sale_bank_amount", saleBankAmount).put("advance_bank_amount", advanceBankAmount)
				.put("sum_back_amount", backCashAmount).put("back_cash_amount", backCashAmount)
				.put("back_bank_amount", backBankAmount).put("imprest_amount", imprestAmount)
				.put("daily_amount", dailyAmount).put("left_amount", leftAmount)
				.put("should_hand_amount", shouldHandAmount)
				.put("real_hand_amount", realHandAmount)
				.put("old_stock", stockMap.get("sumOldStock")).put("new_stock", stockMap.get("sumNewStock"))
				.put("pos_num", stockMap.get("sumPosNum")).put("buyback_num", buybackItemMap.get("itemCount"))
				.put("in_transfer_num", inTransferMap==null?0:inTransferMap.get("sumTransferCount"))
				.put("out_transfer_num", outTransferMap==null?0:outTransferMap.get("sumTransferCount"))
				.put("duo_num", stockMap.get("sumDuoNum")).put("shao_num", stockMap.get("sumShaoNum"))
				.build();
	}

	@Transactional(rollbackFor=Exception.class, readOnly=false, propagation=Propagation.REQUIRED)
	public void saveInfo(Map param) {
		BigDecimal realAmount = new BigDecimal(Tool.toString(param.get("real_amount")));
		BigDecimal shouldAmount = new BigDecimal(Tool.toString(param.get("should_amount")));
		BigDecimal diffAmount = realAmount.subtract(shouldAmount);
		param.put("diff_amount", diffAmount);
		Map user = (Map)param.get("user");
		Maps.put(param, "org_user_id", user.get("id"), "org_user_name", user.get("name")
				, "store_id", user.get("store_id"), "store_name", user.get("store_name"), "id", BusinessTool.generateId());
		shiftDao.saveInfo(param);
	}

	public Map findLastRecord(int storeId) {
		return shiftDao.getLastShiftRecord(storeId);
	}

	public void updateInfo(Map map) {
		shiftDao.updateInfo(map);
	}

	public List queryByPage(int pageNo) {
		Map param = Maps.newHashMap("pageNo", pageNo);
		Tool.initPage(param);
		int start = Tool.toInt(param.get("start"));
		List list = shiftDao.queryByPage(param);
		Iterator iter = list.iterator();
		while(iter.hasNext()) {
			Map map = (Map) iter.next();
			map.put("index", ++start);
			map.put("status_display", ShiftStatusEnum.getEnumByCode(Tool.toInt(map.get("status"))).getDesc());
		}
		return list;
	}

	public int queryCount() {
		return shiftDao.queryCount();
	}

	public Map findShiftById(String id) {
		return shiftDao.findById(id);
	}
	
	public Map findTdcodeByCode(String code, String shelfCode) {
		Map qrcode = qRcodeDao.findQrcodeByKey(code);
		if(qrcode!=null) {
			String shelfTdcode = Tool.toString(qrcode.get("shelf_tdcode"));
			if(!shelfCode.equals(shelfTdcode)) 
				qrcode=null;
			else {
				int productId = Tool.toInt(qrcode.get("commodity_id"));
				Map product = productDao.findProductByKey(productId);
				int spid = Tool.toInt(product.get("spid"));
				Map spec = productDao.findSpecById(spid);
				product.put("spec", spec);
				product.put("sort_display", ProductSortEnum.getEnumByCode(Tool.toInt(product.get("sort"))).getDesc());
				qrcode.put("product", product);
			}
		}
		return qrcode;
	}

	@Transactional(rollbackFor=Exception.class, readOnly=false, propagation=Propagation.REQUIRED)
	public void takeStock(Map map) {
		String codes = Tool.toString(map.get("codes"));
		System.err.println(codes);
		String shelfCode = Tool.toString(map.get("shelfCode"));
		int userId = Tool.toInt(map.get("userId"));
		String userName = Tool.toString(map.get("userName"));
		int storeId = Tool.toInt(map.get("storeId"));
		String storeName = Tool.toString(map.get("storeName"));
		List oldcodeList = qRcodeDao.findQrcodeByShelfCode(shelfCode);
		System.err.println(oldcodeList);
		List oldcopy = new ArrayList(oldcodeList);
		List newcodeList = Arrays.asList(codes.split(","));
		System.err.println(newcodeList);
		List newcopy = new ArrayList(newcodeList);
		Iterator iter = oldcodeList.iterator();
		
		while(iter.hasNext()) {
			Map qrcode = (Map) iter.next();
			String code = Tool.toString(qrcode.get("code"));
			if(newcodeList.contains(code)) {
				newcopy.remove(code);
				oldcopy.remove(qrcode);
			}
		}
		
		Map last = takeStockDao.getLastData();
		String start = null;
		if(last!=null)
			start = Tool.formatDate(Tool.toDate(last.get("create_time")), "yyyy-MM-dd");
		List posList = takeStockDao.getOrdersByShelfCode(Maps.newHashMap("start", start, "type", 1, "code", shelfCode));
		iter = posList.iterator();
		while(iter.hasNext()) {
			Map qrcode = (Map) iter.next();
			String code = Tool.toString(qrcode.get("code"));
			if(oldcopy.contains(code))
				oldcopy.remove(code);
			takeStockDao.unbindQrcodeAndShelf(code);
		}
		
		Map shelf = takeStockDao.getShelfInfoByCode(shelfCode);
		String takeStockId = BusinessTool.generateId();
		takeStockDao.saveTakeStockData(Maps.newHashMap("id", takeStockId, "shelf_code", shelfCode, "user_id", userId
				, "user_name", userName, "old_stock", oldcodeList.size(), "new_stock", newcodeList.size(), "buyback_num", 0
				, "pos_num", posList.size(), "duo_num", newcopy.size(), "shao_num", oldcopy.size()
				, "store_id", storeId, "store_name", storeName, "shelf_name", shelf.get("name")));
		
		List list = new ArrayList();
		iter = newcopy.iterator();
		while(iter.hasNext()) {
			String qrcode = Tool.toString( iter.next());
			Map qrcodeMap = qRcodeDao.findQrcodeByKey(qrcode);
			int productId = Tool.toInt(qrcodeMap.get("commodity_id"));
			Map product = productDao.findProductByKey(productId);
			list.add(Maps.newHashMap("id", BusinessTool.generateId(), "qrcode", qrcode, "product_id", productId
					, "product_name", product==null?"":product.get("name"), "type", 1, "status", 0, "shelf_code", shelfCode
					, "shelf_name", shelf.get("name"), "take_stock_id", takeStockId));
		}
		
		iter = oldcopy.iterator();
		while(iter.hasNext()) {
			Map qrcode = (Map) iter.next();
			int productId = Tool.toInt(qrcode.get("commodity_id"));
			Map product = productDao.findProductByKey(productId);
			list.add(Maps.newHashMap("id", BusinessTool.generateId(), "qrcode", qrcode.get("code"), "product_id", productId
					, "product_name", product==null?"":product.get("name"), "type", 2, "status", 0, "shelf_code", shelfCode
					, "shelf_name", shelf.get("name"), "take_stock_id", takeStockId));
		}
		
		System.err.println(newcopy);
		System.err.println(oldcopy);
		if(!CollectionUtils.isEmpty(list))
			takeStockDao.saveTakeStockDetails(list);
		
		/**
		 * <insert id="saveTakeStockData" parameterType="map">
				insert into take_stock values (#{id}, #{shelf_code}, #{user_id}, #{user_name}, #{old_stock}, #{new_stock}
					, #{buyback_num}, #{pos_num}, #{duo_num}, #{shao_num}, now())
			</insert>
			
			<insert id="saveTakeStockDetails" parameterType="java.util.ArrayList">
				insert into take_stock_detail values
				<foreach collection="list" item="item" index="index" separator=",">
					(#{item.id}, #{item.take_stock_id}, #{item.qrcode}, #{item.product_id},#{item.product_name},#{item.type}
					, #{item.status}, null, null, #{item.shelf_code}, #{item.shelf_name}, now(), null)
				</foreach>
			</insert>
		 */
	}

	public List getTakeStocksByPage(Map param) {
		Tool.initPage(param);
		return takeStockDao.getTakeStocksByPage(param);
	}

	public int getTakeStockCount(Map param) {
		return takeStockDao.getTakeStockCount(param);
	}
	
	public List getDiffDetailsByPage(Map param) {
		Tool.initPage(param);
		List list = takeStockDao.getDiffDetailsByPage(param);
		Iterator iter = list.iterator();
		while(iter.hasNext()) {
			Map map = (Map) iter.next();
			int productId = Tool.toInt(map.get("product_id"));
			Map product = productDao.findProductByKey(productId);
			int spid = Tool.toInt(product.get("spid"));
			Map spec = productDao.findSpecById(spid);
			product.put("spec", spec);
			product.put("sort_display", ProductSortEnum.getEnumByCode(Tool.toInt(product.get("sort"))).getDesc());
			map.put("product", product);
			String qrcode = Tool.toString(map.get("qrcode"));
			Map qrcodeMap = qRcodeDao.findQrcodeByKey(qrcode);
			map.put("qrcodeMap", qrcodeMap);
			map.put("status_display", TakeStockStatusEnum.getEnumByCode(Tool.toInt(map.get("status"))).getDesc());
		}
		return list;
	}

	public int getDiffDetailsCount(Map param) {
		return takeStockDao.getDiffDetailsCount(param);
	}

	@Transactional(rollbackFor=Exception.class, readOnly=false, propagation=Propagation.REQUIRED)
	public void confirm(Map param) {
		takeStockDao.diffConfirm(param);
	}

}
